#ifndef __SOFT_I2C_H
#define __SOFT_I2C_H

#include <stdint.h>
#include <stdbool.h>

typedef enum {
	SOFT_I2C_GPIO_LOW = 0,
	SOFT_I2C_GPIO_HIGH = 1,
} soft_i2c_gpio_level;

typedef enum {
	SOFT_I2C_GPIO_IN = 0,
	SOFT_I2C_GPIO_OUT = 1,
} soft_i2c_gpio_direction;

typedef enum {
	SOFT_I2C_START = 0,
	SOFT_I2C_STOP = 0,
	SOFT_I2C_WR = 0,
	SOFT_I2C_RD = 0X01,
	SOFT_I2C_NOSTART = 0X02,
	SOFT_I2C_NOSTOP = 0X04,
} soft_i2c_flag;

typedef struct {
	soft_i2c_flag flag;
	uint32_t len;
	uint8_t *buf;
} soft_i2c_xfer;

typedef struct __soft_i2c_ctrl soft_i2c_ctrl;

/* implement by user */
typedef void (*soft_i2c_gpio_set_direction)(uint32_t pin, soft_i2c_gpio_direction direction);
typedef void (*soft_i2c_gpio_set_level)(uint32_t pin, soft_i2c_gpio_level level);
typedef soft_i2c_gpio_level (*soft_i2c_gpio_get_level)(uint32_t pin);
typedef void (*soft_i2c_delay_us)(uint32_t us);

/* user interface */
typedef int (*soft_i2c_transfer)(soft_i2c_ctrl *ctrl, uint8_t chip, soft_i2c_xfer *xfer, uint32_t len);
typedef int (*soft_i2c_read_reg)(soft_i2c_ctrl *ctrl, uint8_t chip, uint8_t reg, uint8_t *val);
typedef int (*soft_i2c_write_reg)(soft_i2c_ctrl *ctrl, uint8_t chip, uint8_t reg, uint8_t val);

struct __soft_i2c_ctrl {
	uint32_t sda;
	uint32_t scl;
	soft_i2c_gpio_set_direction gpio_set_direction;
	soft_i2c_gpio_set_level gpio_set_level;
	soft_i2c_gpio_get_level gpio_get_level;
	soft_i2c_delay_us delay_us;
	
	/* interface */
	soft_i2c_transfer transfer;
	soft_i2c_read_reg read_reg;
	soft_i2c_write_reg write_reg;
	
	/* private */
	void (*gpio_init)(soft_i2c_ctrl *ctrl);
	void (*i2c_start)(soft_i2c_ctrl *ctrl);
	void (*i2c_stop)(soft_i2c_ctrl *ctrl);
	void (*i2c_ack)(soft_i2c_ctrl *ctrl);
	void (*i2c_nack)(soft_i2c_ctrl *ctrl);
	bool (*i2c_wait_ack)(soft_i2c_ctrl *ctrl);
	void (*write_8bit)(soft_i2c_ctrl *ctrl, uint8_t byte);
	uint8_t (*read_8bit)(soft_i2c_ctrl *ctrl);
};

void soft_i2c_init(soft_i2c_ctrl *ctrl);

#endif
